@page "/Initialize"
@using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Options
@using Passwordless.AdminConsole.Services.PasswordlessManagement
@using Passwordless.Common.Models.Apps
@using Passwordless.AdminConsole.Db
@using Passwordless.AdminConsole.Identity
@using Microsoft.AspNetCore.Identity
@using Passwordless.AdminConsole.Models
@using System.ComponentModel.DataAnnotations
@attribute [AllowAnonymous]

@inject ISetupService SetupService
@inject IOptionsSnapshot<PasswordlessManagementOptions> ManagementOptions
@inject ConsoleDbContext DbContext
@inject NavigationManager NavigationManager
@inject IApplicationService ApplicationService
@inject IDataService DataService
@inject TimeProvider TimeProvider
@inject UserManager<ConsoleAdmin> UserManager
@inject ILogger<Initialize> Logger
@inject IPasswordlessManagementClient PasswordlessManagementClient

<h3>🚀 Let's set up the Admin Console</h3>
<Alert Style="@ContextualStyles.Warning" class="mt-5">Admin Console is configured to use the API at <strong>@ManagementOptions.Value.ApiUrl</strong></Alert>

<Panel>
    @if (!IsFormSubmitted)
    {
        <p>The Admin Console is missing either migrations or ApiKeys for the Passwordless.dev API, proceed with the setup wizard below.</p>

        <p>Upon completing the form, a separate application in the Passwordless.dev API is created to hold the credentials for administrators of the Admin Console.</p>

        <EditForm
            Model="Form"
            FormName="AdminConsoleCreateForm"
            OnValidSubmit="OnAdminConsoleCreateFormSubmitted"
            class="space-y-6">
            <div class="sm:w-full sm:max-w-md">
                <label class="block text-sm font-medium leading-6 text-gray-900 my-2" for="Name">
                    Admin Name
                    <InputText id="Name" @bind-Value="@Form.AdminName" class="text-input" placeholder="Hubert J. Farnsworth"/>
                </label>
                <label class="block text-sm font-medium leading-6 text-gray-900 my-2" for="Email">
                    Admin Email
                    <InputText id="Email" @bind-Value="@Form.AdminEmail" type="email" class="text-input" placeholder="hubert@planetexpress.com"/>
                </label>
                <p class="mt-3 text-sm leading-6 text-gray-600">This email will be limited to the admin organisation and cannot be used to create another organisation later.</p>

                <button class="btn-primary mt-3" type="submit">Initialize the Admin Console</button>
            </div>
        </EditForm>
    }

    @if (IsFormSubmitted)
    {
        <p>@ProcessMessage</p>
    }

    @if (PasswordlessOptions is not null)
    {
        <p><strong>Keep these values secret</strong>. Add these values to your Admin Console configuration:</p>

        <code style="white-space: pre;" lang="json">@JsonSerializer.Serialize(PasswordlessOptions, _jsonSerializerOptions)</code>

        <p>When self-hosting, make sure to mount a persistent volume to write your configuration. Read more <a class="link-blue" href="https://docs.passwordless.dev/guide/self-hosting/configuration.html#volumes">here</a>.</p>

        <p>After doing this, <a class="link-blue" href="/">navigate to the home page</a> and enter the Admin Email used here to receive a magic link.</p>
    }
</Panel>

@code {

    private readonly JsonSerializerOptions _jsonSerializerOptions = new ()
    {
        WriteIndented = true
    };

    [SupplyParameterFromForm(FormName = "AdminConsoleCreateForm")]
    public AdminConsoleCreateForm Form { get; set; } = new();

    public bool IsFormSubmitted { get; set; }

    public string ProcessMessage { get; set; } = string.Empty;

    public PasswordlessOptions? PasswordlessOptions { get; set; }

    protected override async Task OnInitializedAsync()
    {
        if (await SetupService.HasSetupCompletedAsync())
        {
            NavigationManager.NavigateTo("/");
        }
    }

    private async Task OnAdminConsoleCreateFormSubmitted()
    {
        IsFormSubmitted = true;

        Models.Organization organization;
        var now = TimeProvider.GetUtcNow().UtcDateTime;

        CreateAppResultDto? appCreationResult;

        // Create app in the API
        try
        {
            const string appName = "adminconsole";
            appCreationResult = await PasswordlessManagementClient.CreateApplicationAsync(appName, new CreateAppDto
            {
                AdminEmail = Form.AdminEmail,
                MagicLinkEmailMonthlyQuota = 2000
            });
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Failed to create app in Api.");
            ProcessMessage = "Failed to create app in Api. Please see Console for a detailed error message";
            return;
        }

        await DbContext.Database.MigrateAsync();

        // Create org
        try
        {
            organization = new Models.Organization
            {
                Name = "Admin Console",
                InfoOrgType = OrganizationType.Company,
                InfoUseCase = UseCaseType.Both,
                CreatedAt = now
            };
            await DataService.CreateOrganizationAsync(organization);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Failed to create org.");
            ProcessMessage = "Failed to create org. Please see Console for a detailed error message.";
            return;
        }

        // Create admin
        try
        {
            var user = new ConsoleAdmin
            {
                UserName = Form.AdminEmail,
                Email = Form.AdminEmail,
                OrganizationId = organization.Id,
                Name = Form.AdminName
            };

            await UserManager.SetUserNameAsync(user, Form.AdminEmail);
            await UserManager.SetEmailAsync(user, Form.AdminEmail);
            await UserManager.CreateAsync(user);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Failed to create admin.");
            ProcessMessage = "Failed to create admin. Please see Console for a detailed error message.";
            return;
        }

        // create app in org
        try
        {
            await ApplicationService.CreateApplicationAsync(new Application
            {
                Id = "adminconsole",
                Name = "Admin Console",
                Description = "This is the AdminConsole application within AdminConsole.",
                CreatedAt = now,
                OrganizationId = organization.Id,
                ApiKey = appCreationResult.ApiKey2,
                ApiSecret = appCreationResult.ApiSecret2,
                ApiUrl = ManagementOptions.Value.ApiUrl,
                Onboarding = new Onboarding
                {
                    ApiKey = appCreationResult.ApiKey1,
                    ApiSecret = appCreationResult.ApiSecret1,
                    SensitiveInfoExpireAt = now.AddDays(7)
                },
                BillingPlan = "Free"
            });
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Failed to create app in AdminConsole.");
            ProcessMessage = "Failed to create app in AdminConsole. Please see Console for a detailed error message.";
            return;
        }

        PasswordlessOptions = new PasswordlessOptions
        {
            ApiUrl = ManagementOptions.Value.ApiUrl,
            ApiKey = appCreationResult.ApiKey1,
            ApiSecret = appCreationResult.ApiSecret1
        };

        ProcessMessage = "✅ Admin Console has been initialized successfully.";
    }

    public sealed class AdminConsoleCreateForm
    {
        [Required] public string AdminName { get; set; } = string.Empty;
        [Required, EmailAddress] public string AdminEmail { get; set; } = string.Empty;
    }
}